home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Libris Britannia 4
/
science library(b).zip
/
science library(b)
/
DJGPP
/
DJSRC111.ZIP
/
go32
/
graphics.c
< prev
next >
Wrap
C/C++ Source or Header
|
1993-10-11
|
14KB
|
430 lines
/* This is file GRAPHICS.C */
/*
** Copyright (C) 1993 DJ Delorie, 24 Kirsten Ave, Rochester NH 03867-2954
** Copyright (C) 1993 Grzegorz Mazur, gbm@ii.pw.edu.pl
**
** This file is distributed under the terms listed in the document
** "copying.dj", available from DJ Delorie at the address above.
** A copy of "copying.dj" should accompany this file; if not, a copy
** should be available from where this file was obtained. This file
** may not be distributed without a verbatim copy of "copying.dj".
**
** This file is distributed WITHOUT ANY WARRANTY; without even the implied
** warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*/
#pragma inline
/* History:42,23 */
#include <dos.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <stdio.h>
#include <alloc.h>
#include <string.h>
#include <io.h>
#include "gotypes.h"
#include "paging.h"
#include "graphics.h"
#include "tss.h"
#include "gdt.h"
#include "grdriver.h"
extern fillgdt(int sel, word32 limit, word32 base, word8 type, int G);
/* DJ - tcc 2.0 can't handle far arrays */
/* extern char far builtin_driver_code[]; */
extern char builtin_driver_code[];
/* DJ - end */
extern int builtin_driver_size;
/* driver version defs */
#define BAD (-2) /* tried loading -- driver reports error */
#define UNK (-1) /* unknown -- no graphics call made yet */
#define GRD 0 /* DJ's original 256 color driver */
#define GRN 1 /* GRX 1.01+ programmable color driver */
#define VDR 2 /* GRX 1.03+ VESA compatible extended driver */
/* driver stuff */
static GrDriverHeader far *driver = NULL;
static char *drv_name = NULL;
static char drv_version = UNK;
/* driver default parameters filled out from GO32 env. var. */
int gr_def_tw = 0;
int gr_def_th = 0;
int gr_def_gw = 0;
int gr_def_gh = 0;
int gr_def_numcolor = 0;
/* Direct INT 10h function calls with AX >= this value to the 'graphics_assist' function */
/* One of the 'graphics_assist' functions can be used to reset this to 0xff00 */
/* Older versions of GRX used INT 10h, AH=0FEh to get the driver mode parameters. */
/* GRX 1.03+ does not use this call any more. Desqview also seems to be using the */
/* INT 10h, AH=0FEh call. By allowing to reset this value to 0xff00, GO32 will support */
/* both. Later when GRX 1.03 and later versions will be more out for some time we can */
/* change the default... */
word16 gr_assist_func_start = 0xfe00;
/* two graphics page tables */
word32 far *graphics_pt1 = NULL;
word32 far *graphics_pt2 = NULL;
word32 graphics_pt1_lin;
word32 graphics_pt2_lin;
/* pointers necessary for moving the graphics page tables in the page directory */
/* they point to the start of the graphics region in the PD-s */
word32 far *graphics_pd;
word8 far *graphics_pd_seg;
word32 graphics_pd_lin;
word32 graphics_pd_seg_lin;
/* current location of the two page tables */
word16 graphics_pt1_loc;
word16 graphics_pt2_loc;
/* the protected mode paging function */
word32 gr_paging_func;
/* linear pointers to prepared page table segments */
word32 gr_rw_table_lin;
word32 gr_ro_table_lin;
word32 gr_wo_table_lin;
/* other parameters for protected mode paging routine */
word32 gr_sgl_page_size = 16; /* R/W page size in 4kByte units */
word32 gr_r_w_page_size = 16; /* split page sizes in 4kByte units */
word8 gr_sgl_page_shift = 4; /* log2 of the R/W page size in 4kByte units */
word8 gr_r_w_page_shift = 4; /* log2 of the split page sizes in 4kByte units */
word8 gr_rw_page_offset = 0; /* diff between two windows in R/W mode (ATI!) */
/* prepared page table segments: */
/* paging code can use rep movsl-s instead of fiddling with bits */
/* allocate enough space for 128kByte graphics map */
/* also contains the real mode paging parameter transfer buffer */
/* DJ - tcc 2.0 can't do far arrays */
/* static word32 far gr_prepared_tables[3*(128/4) + 4 + 1]; */
static word32 gr_prepared_tables[3*(128/4) + 4 + 1];
/* DJ - end */
static word32 far *gr_rw_table;
static word32 far *gr_ro_table;
static word32 far *gr_wo_table;
/* stuff for the real-mode paging function interface */
word32 real_paging_buffer_lin; /* linear address of param passing buffer */
word32 real_paging_buffer_virt; /* virtual address of param passing buffer */
word32 real_paging_func_virt; /* virtual address of the arena paging function */
extern void far real_paging_routine(void);
extern void far arena_real_paging_func(void);
static void far dummy_paging_routine(void)
{
return;
}
static void fbzero(void far *addr,int size)
{
asm les di,dword ptr addr;
asm mov cx,word ptr size;
asm shr cx,1;
asm je done;
asm xor ax,ax;
asm rep stosw;
done:
return;
}
static void setup_paging_routine(void)
{
word16 gr_seg = (drv_version <= UNK) ? FP_SEG(dummy_paging_routine) : FP_SEG(driver);
word16 gr_off = (drv_version <= UNK) ? FP_OFF(dummy_paging_routine) : driver->paging_routine;
word32 rw_addr = 0x000a0000L;
word32 ro_addr = 0x000a0000L;
word32 wo_addr = 0x000a0000L;
int i;
if(drv_version == VDR) {
rw_addr = wo_addr = (word32)driver->wr_page_start << 4;
ro_addr = (driver->rd_page_start == 0xffff) ?
rw_addr :
(word32)driver->rd_page_start << 4;
gr_sgl_page_shift = gr_r_w_page_shift = driver->page_size_shift;
gr_rw_page_offset = 0;
if(ro_addr > wo_addr) {
/* ATI style paging: two split READ/WRITE 32kByte pages */
/* it is handled by mapping the two pages continguously in R/W mode to */
/* form a single 64K page. In separate R and W mode we have two */
/* 32 kByte pages. For this we need an offset of one between the two */
/* page indices in R/W mode */
gr_sgl_page_shift++;
gr_rw_page_offset = 1;
}
gr_sgl_page_size = 1 << gr_sgl_page_shift;
gr_r_w_page_size = 1 << gr_r_w_page_shift;
if(driver->driver_options & GRD_PROTECTED_PAGING) {
if(driver->VESA_paging_fnc != 0L) {
fillgdt(g_VESAfunc, 0xffff,
(word32)FP_SEG(driver->VESA_paging_fnc) * 16L,
0x9a, 0
);
driver->VESA_paging_fnc = MK_FP(
(g_VESAfunc << 3),
FP_OFF(driver->VESA_paging_fnc)
);
}
}
else {
gr_seg = FP_SEG(real_paging_routine);
gr_off = FP_OFF(real_paging_routine);
}
}
fillgdt(g_grdr, 0xffff, (word32)gr_seg << 4, 0x9a, 0);
gr_paging_func = (word32)MK_FP((g_grdr << 3),gr_off);
fbzero(gr_prepared_tables,sizeof(gr_prepared_tables));
if(graphics_pt1) {
fbzero(graphics_pt1,4096);
fbzero(graphics_pt2,4096);
}
for(i = 0; i < (int)gr_sgl_page_size; i++) {
gr_rw_table[i] = rw_addr | (PT_W | PT_U | PT_P);
rw_addr += 4096;
}
for(i = 0; i < (int)gr_r_w_page_size; i++) {
gr_wo_table[i] = wo_addr | (PT_W | PT_U | PT_P);
gr_ro_table[i] = ro_addr | (PT_U | PT_P);
wo_addr += 4096;
ro_addr += 4096;
}
}
void setup_graphics_driver(char *name)
{
word32 far *real_paging_buf;
if(name != NULL) drv_name = strdup(name);
gr_rw_table = MK_FP(FP_SEG(gr_prepared_tables),((FP_OFF(gr_prepared_tables) + 3) & ~3));
gr_ro_table = gr_rw_table + 128/4;
gr_wo_table = gr_ro_table + 128/4;
gr_rw_table_lin = ptr2linear(gr_rw_table);
gr_ro_table_lin = ptr2linear(gr_ro_table);
gr_wo_table_lin = ptr2linear(gr_wo_table);
real_paging_buf = gr_wo_table + 128/4;
real_paging_buffer_lin = ptr2linear(real_paging_buf);
real_paging_buffer_virt = real_paging_buffer_lin + 0xe0000000L;
real_paging_func_virt = ptr2linear(arena_real_paging_func) + 0xe0000000L;
setup_paging_routine();
}
static void load_graphics_driver(void)
{
int far (*init_func)(void);
char *try,*opt = NULL;
char far *p1,far *p2;
FILE *drvfile;
int size,ch;
if(drv_version != UNK) return;
if(drv_name) {
for(try = drv_name; (try = strchr(try,':')) != NULL; try++) {
if(try[1] == ':') {
opt = &try[2];
*try = '\0';
break;
}
}
if((*drv_name != '\0') && ((drvfile = fopen(drv_name,"rb")) != NULL)) {
try = NULL;
size = (int)filelength(fileno(drvfile));
if((size >= 100) && ((size <= builtin_driver_size) || ((try = malloc(size + 16)) != NULL))) {
p1 = (size <= builtin_driver_size) ? builtin_driver_code : (char far *)try;
p1 = MK_FP((FP_SEG(p1) + ((FP_OFF(p1) + 15) >> 4)),0);
driver = (GrDriverHeader far *)p1;
while(--size >= 0) {
if((ch = fgetc(drvfile)) == EOF) {
/* bad driver file, disk error, etc..? */
if(try || (p1 == (char *)driver)) {
/* fortunately we still have the original */
if(try) free(try);
driver = NULL;
}
else {
/* no help, even the built-in driver is screwed up now */
drv_version = BAD;
}
break;
}
*p1++ = ch;
}
}
fclose(drvfile);
}
}
if(drv_version != BAD) {
drv_version = GRD;
if(!driver) {
driver = MK_FP((FP_SEG(builtin_driver_code) + ((FP_OFF(builtin_driver_code) + 15) >> 4)),0);
if(FP_OFF(builtin_driver_code) & 15) {
size = builtin_driver_size;
p1 = (char far *)driver + size;
p2 = builtin_driver_code + size;
while(--size >= 0) *(--p1) = *(--p2);
}
}
if(driver->driver_flags & GRD_NEW_DRIVER) {
p1 = (char far *)driver->vdr_magic;
p2 = ".VDR driver";
while(*p1 && (*p1 == *p2)) p1++,p2++;
drv_version = (*p1 == *p2) ? VDR : GRN;
if((drv_version == VDR) && opt) while(*opt != '\0') {
switch(*opt) {
case 'P':
case 'p':
driver->driver_options |= GRD_PROTECTED_PAGING;
break;
case 'F':
case 'f':
driver->driver_options |= GRD_FAST_256_MODE;
break;
case '5':
driver->driver_options |= GRD_15_PLANE_MODE;
break;
}
opt++;
}
init_func = MK_FP(FP_SEG(driver),driver->driver_init_routine);
_AX = FP_SEG(driver);
asm push ds;
asm mov ds,ax;
asm call dword ptr ss:[init_func];
asm pop ds;
if(_AX == 0) {
/* You may want to do something more appropriate here */
fputs("Graphics initialization error -- probably incorrect driver\n",stderr);
drv_version = BAD;
}
}
switch(drv_version) {
case VDR:
case GRN:
if(gr_def_numcolor > 0) driver->def_numcolor = gr_def_numcolor;
case GRD:
if(gr_def_tw > 0) driver->def_tw = gr_def_tw;
if(gr_def_th > 0) driver->def_th = gr_def_th;
if(gr_def_gw > 0) driver->def_gw = gr_def_gw;
if(gr_def_gh > 0) driver->def_gh = gr_def_gh;
}
}
if(drv_name) free(drv_name);
setup_paging_routine();
}
static word32 add_driver_version(word16 flags)
{
switch(drv_version) {
case GRD: return(flags | GR_DRV_VER_GRD);
case GRN: return(flags | GR_DRV_VER_GRN);
case VDR: return(flags | GR_DRV_VER_VDR);
default: return(-1L);
}
}
void graphics_assist(void)
{
void far (*driver_func)(void);
word16 mode,cnum,cols,rows;
switch((word16)tss_ptr->tss_eax & 0xff00) {
case 0xff00: /* graphics assist function */
switch(mode = ((word16)tss_ptr->tss_eax & 0x00ff)) {
case 0x00ff: /* SUB-FNC 0xFF: make GO32 Desqview compatible */
gr_assist_func_start = 0xff00;
break;
case 0x00fe: /* SUB-FNC 0xFE: return driver header adr */
if(drv_version == UNK) load_graphics_driver();
/* don't add 0xe0000000 -- GRX will figure whether running under DPMI or VCPI */
tss_ptr->tss_eax = (drv_version == BAD) ? 0L : (word32)ptr2linear(driver);
break;
case 0x00fd: /* SUB-FNC 0xFD: call pg fnc in real mode */
if(drv_version < GRD) break;
driver_func = MK_FP(FP_SEG(driver),driver->paging_routine);
_AX = (word16)tss_ptr->tss_ebx;
asm push si;
asm push di;
asm call dword ptr ss:[driver_func];
asm pop di;
asm pop si;
break;
case 0x00fc: /* SUB-FNC 0xFC: set virtual screen start */
if(drv_version != VDR) break;
cols = (word16)tss_ptr->tss_ecx;
rows = (word16)tss_ptr->tss_edx;
driver_func = MK_FP(FP_SEG(driver),driver->set_screen_start);
_AX = FP_SEG(driver);
asm mov cx,word ptr cols;
asm mov dx,word ptr rows;
asm push ds;
asm mov ds,ax;
asm call dword ptr ss:[driver_func];
asm pop ds;
break;
default: /* mode set */
if(drv_version == UNK) load_graphics_driver();
switch(drv_version) {
case GRD:
if(mode > 8) mode = 8;
case GRN:
if(mode > 9) mode = 9;
case VDR:
if((mode & 0x7f) > 10) mode = (mode & 0x80) + 10;
cnum = (word16)tss_ptr->tss_ebx;
cols = (word16)tss_ptr->tss_ecx;
rows = (word16)tss_ptr->tss_edx;
driver_func = MK_FP(FP_SEG(driver),driver->modeset_routine);
_AX = FP_SEG(driver);
asm push ds;
asm push ax;
asm mov ax,word ptr mode;
asm mov bx,word ptr cnum;
asm mov cx,word ptr cols;
asm mov dx,word ptr rows;
asm pop ds;
asm call dword ptr ss:[driver_func];
asm pop ds;
asm mov word ptr cnum,bx;
asm mov word ptr cols,cx;
asm mov word ptr rows,dx;
tss_ptr->tss_ebx = add_driver_version(cnum);
tss_ptr->tss_ecx = (word32)cols;
tss_ptr->tss_edx = (word32)rows;
setup_paging_routine();
break;
default:
/* BAD driver -- only perform text mode sets */
if(mode < 4) {
_AX = 3;
geninterrupt(0x10);
tss_ptr->tss_ebx = 0;
tss_ptr->tss_ecx = 80;
tss_ptr->tss_edx = 25;
break;
}
tss_ptr->tss_ebx = (-1); /* signal error */
break;
}
}
break;
case 0xfe00: /* old style driver mode info */
if(drv_version == UNK) load_graphics_driver();
tss_ptr->tss_ebx = (drv_version < GRD) ? -1L : add_driver_version(driver->driver_flags);
tss_ptr->tss_ecx = (drv_version < GRN) ? 0L : 0xe0000000L + ptr2linear(MK_FP(FP_SEG(driver),driver->text_table));
tss_ptr->tss_edx = (drv_version < GRN) ? 0L : 0xe0000000L + ptr2linear(MK_FP(FP_SEG(driver),driver->graphics_table));
break;
}
}